
#include <BTreeWidget>

#include <BTreeItem>
#include "member_BTreeItem.h"
#include "member_BTreeWidget.h"

using namespace BWE;

#define member					(*(member_BTreeItem*)_ptr)
#define member_allocate()		_ptr = new member_BTreeItem(this)
#define member_release()		delete (member_BTreeItem*)_ptr

BTreeItem::BTreeItem(BTreeItem* parent)
{
	member_allocate();
	setParent(parent);
	member.dirtyTree();
}
BTreeItem::BTreeItem(const BString& text, BTreeItem* parent)
{
	member_allocate();
	setText(text);
	setParent(parent);
	member.dirtyTree();
}
BTreeItem::BTreeItem(Graph graph, const BString& text, Form form)
{
	member_allocate();
	setGraph(graph);
	setText(text);
	setForm(form);
	member.dirtyTree();
}
BTreeItem::BTreeItem(BIcon* icon, const BString& text, Form form)
{
	member_allocate();
	setIcon(icon);
	setText(text);
	setForm(form);
	member.dirtyTree();
}
BTreeItem::BTreeItem(BImage* image, const BString& text, Form form)
{
	member_allocate();
	setImage(image);
	setText(text);
	setForm(form);
	member.dirtyTree();
}
BTreeItem::BTreeItem(BWidget* widget, const BString& text, Form form)
{
	member_allocate();
	setWidget(widget);
	setText(text);
	setForm(form);
	member.dirtyTree();
}
BTreeItem::~BTreeItem()
{
	member_release();
}

void BTreeItem::setExpanded(bool expanded)
{
	if (member.expanded != expanded)
	{
		if (member.tree)
		{
			if (expanded)
				member.tree->expand(this);
			else
				member.tree->shrink(this);
			member.dirtyTree();
		}
		else
		{
			member.expanded = expanded;
		}
	}
}
bool BTreeItem::expanded() const
{
	return member.expanded;
}

void BTreeItem::setSelected(bool selected)
{
	if (member.tree && member.selected != selected)
	{
		member.tree->setItemSelected(this, selected);
	}
}
bool BTreeItem::isSelected() const
{
	return member.selected;
}

void BTreeItem::setVisible(bool visible)
{
	if (member.visible != visible)
	{
		member.visible = visible;
		member.dirtyTree();
		if (member.selected)
			this->setSelected(false);
	}
}
bool BTreeItem::visible() const
{
	return member.visible;
}

void BTreeItem::setAlign(Align align)
{
	if (member.ia_align != align)
	{
		member.ia_align = align;
		member.adjustRect(member.rect);
		member.dirtyTree();
	}
}
Align BTreeItem::align() const
{
	return member.ia_align;
}

void BTreeItem::setForm(Form form)
{
	if (member.ia_form != form)
	{
		member.ia_form = form;
		member.dirty = true;
		member.dirtyTree();
	}
}
Form BTreeItem::form() const
{
	return member.ia_form;
}

void BTreeItem::setColor(BByte r, BByte g, BByte b, BByte a)
{
	setColor(BColor(r, g, b, a));
}
void BTreeItem::setColor(const BColor& color)
{
	if (member.color != color)
	{
		member.color = color;
		member.dirtyTree();
	}
}
const BColor& BTreeItem::color() const
{
	return member.color;
}

void BTreeItem::setGraph(Graph graph)
{
	if (member.graph != graph)
	{
		member.graph = graph;
		member.dirty = true;
		member.dirtyTree();
	}
}
Graph BTreeItem::graph() const
{
	return member.graph;
}

void BTreeItem::setImage(BImage* image)
{
	if (member.image != image)
	{
		member.image = image;
		member.dirty = true;
		member.dirtyTree();
	}
}
BImage* BTreeItem::image() const
{
	return member.image;
}

void BTreeItem::setIcon(BIcon* icon)
{
	if (member.icon != icon)
	{
		member.icon = icon;
		member.dirty = true;
		member.dirtyTree();
	}
}
BIcon* BTreeItem::icon()
{
	return member.icon;
}
const BIcon* BTreeItem::icon() const
{
	return member.icon;
}

void BTreeItem::setFont(BFont* font)
{
	if (member.localFont != font)
	{
		member.localFont = font;
		member.dirty = true;
		member.dirtyTree();
	}
}
const BFont* BTreeItem::font() const
{
	if (member.localFont)
		return member.localFont;
	if (member.tree)
		return member.tree->font();
	return 0;
}

void BTreeItem::setText(const BString& text)
{
	if (member.text != text)
	{
		member.text = text;
		member.dirty = true;
		member.dirtyTree();
	}
}
const BString& BTreeItem::text() const
{
	return member.text;
}

void BTreeItem::setWidget(BWidget* widget)
{
	if (member.widget != widget)
	{
		if (member.tree)
			member.tree->removeChild(member.widget);
		member.widget = widget;
		if (member.tree)
			member.tree->addChild(member.widget);
		if (member.widget)
			member.widget->setRect(member.rect);
		member.dirty = true;
		member.dirtyTree();
	}
}
BWidget* BTreeItem::widget()
{
	return member.widget;
}
const BWidget* BTreeItem::widget() const
{
	return member.widget;
}

void BTreeItem::setParent(BTreeItem* parent)
{
	if(member.parent != parent)
	{
		BHolder<BTreeItem> holder;
		if(member.parent)
		{
			member.dirtyTree();
			holder = this;
			member.parent->removeChild(this);
		}
		if(parent)
		{
			parent->addChild(this);
			holder = 0;
			member.dirtyTree();
		}
	}
}
BTreeItem* BTreeItem::parent()
{
	return member.parent;
}
const BTreeItem* BTreeItem::parent() const
{
	return member.parent;
}

bool BTreeItem::addChild(BTreeItem* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	if (member.children.contain(child))
		return true;
	member.children.append(child);
	if (item_member(child)->parent)
		item_member(child)->parent->removeChild(child);
	item_member(child)->parent = this;
	if(item_member(child)->tree)
		item_member(child)->tree->removeTopItem(child);
	item_member(child)->attach(member.tree);
	member.dirtyTree();
	return true;
}
BTreeItem* BTreeItem::addChild(const BString& text)
{
	BTreeItemHolder item = new BTreeItem(text);
	if (addChild(item))
		return item;
	return 0;
}
bool BTreeItem::insertChild(int pos, BTreeItem* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	int index = member.children.find(child);
	if (index < member.children.size())
	{
		member.children.move(index, pos);
	}
	else
	{
		member.children.insert(pos, child);
		if (item_member(child)->parent)
			item_member(child)->parent->removeChild(child);
		item_member(child)->parent = this;
		if (item_member(child)->tree)
			item_member(child)->tree->removeTopItem(child);
		item_member(child)->attach(member.tree);
	}
	member.dirtyTree();
	return true;
}
bool BTreeItem::removeChild(BTreeItem* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	if (!member.children.contain(child))
		return false;
	if (member.tree)
	{
		tree_member(member.tree)->selectedItems.remove(child);
	}
	item_member(child)->parent = 0;
	item_member(child)->detach(member.tree);
	member.children.remove(child);
	member.dirtyTree();
	return true;
}
void BTreeItem::clearChildren()
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BTreeItem* child = member.children[i];
		item_member(child)->parent = 0;
		item_member(child)->detach(member.tree);
	}
	member.children.clear();
	member.dirtyTree();
}

int BTreeItem::childCount() const
{
	return member.children.size();
}
BTreeItem* BTreeItem::child(int index)
{
	return member.children[index].ptr();
}
const BTreeItem* BTreeItem::child(int index) const
{
	return member.children[index].ptr();
}

BTreeItem* BTreeItem::child(const BString& text)
{
	for(int i = 0; i < member.children.size(); i++)
	{
		const BString& childText = member.children[i]->text();
		if (childText == text)
			return member.children[i].ptr();
	}
	return 0;
}
const BTreeItem* BTreeItem::child(const BString& text) const
{
	for(int i = 0; i < member.children.size(); i++)
	{
		if(member.children[i]->text() == text)
			return member.children[i].ptr();
	}
	return 0;
}

BTreeItem* BTreeItem::childOfAsset(const BValue& asset)
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BTreeItem* child = member.children[i];
		if (child->asset() == asset)
			return child;
	}
	return 0;
}
const BTreeItem* BTreeItem::childOfAsset(const BValue& asset) const
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BTreeItem* child = member.children[i];
		if (child->asset() == asset)
			return child;
	}
	return 0;
}

BTreeItem* BTreeItem::findByText(const BString& text)
{
	if (member.text == text)
		return this;
	for (int i = 0; i < member.children.size(); i++)
	{
		BTreeItem* child = member.children[i];
		BTreeItem* item = child->findByText(text);
		if (item)
			return item;
	}
	return 0;
}
const BTreeItem* BTreeItem::findByText(const BString& text) const
{
	if (member.text == text)
		return this;
	for (int i = 0; i < member.children.size(); i++)
	{
		const BTreeItem* child = member.children[i];
		const BTreeItem* item = child->findByText(text);
		if (item)
			return item;
	}
	return 0;
}

BTreeItem* BTreeItem::findByAsset(const BValue& asset)
{
	if (asset.empty())
		return 0;
	if (this->asset() == asset)
		return this;
	for (int i = 0; i < member.children.size(); i++)
	{
		BTreeItem* child = member.children[i];
		BTreeItem* item = child->findByAsset(asset);
		if (item)
			return item;
	}
	return 0;
}
const BTreeItem* BTreeItem::findByAsset(const BValue& asset) const
{
	if (asset.empty())
		return 0;
	if (this->asset() == asset)
		return this;
	for (int i = 0; i < member.children.size(); i++)
	{
		const BTreeItem* child = member.children[i];
		const BTreeItem* item = child->findByAsset(asset);
		if (item)
			return item;
	}
	return 0;
}

BTreeItem* BTreeItem::create(const BString& path)
{
	int end = path.find('/');
	if (end == path.size())
	{
		BTreeItem* item = this->child(path);
		if (item == 0)
			item = this->addChild(path);
		return item;
	}
	BString text;
	path.substr(text, 0, end);
	BTreeItem* item = this->child(text);
	if (item == 0)
	{
		item = this->addChild(text);
	}
	int pos = end + 1;
	while (item && pos < path.size())
	{
		end = path.find('/', pos);
		path.substr(text, pos, end);
		BTreeItem* child = item->child(text);
		if (child == 0)
			child = item->addChild(text);
		item = child;
		pos = end + 1;
	}
	return item;
}

BTreeItem* BTreeItem::locate(const BString& path)
{
	if (path.empty())
		return this;
	BStringList textlst = path.split('/');
	BTreeItem* node = this->child(textlst.first());
	textlst.remove(0);
	while (node && textlst.size())
	{
		const BString& text = textlst.first();
		node = node->child(text);
		textlst.remove(0);
	}
	return node;
}
const BTreeItem* BTreeItem::locate(const BString& path) const
{
	if (path.empty())
		return this;
	BStringList textlst = path.split('/');
	const BTreeItem* node = this->child(textlst.first());
	textlst.remove(0);
	while (node && textlst.size())
	{
		const BString& text = textlst.first();
		node = node->child(text);
		textlst.remove(0);
	}
	return node;
}

BTreeItem* BTreeItem::root()
{
	BTreeItem* item = this;
	while (item_member(item)->parent)
		item = item_member(item)->parent;
	return item;
}
const BTreeItem* BTreeItem::root() const
{
	const BTreeItem* item = this;
	while (item_member(item)->parent)
		item = item_member(item)->parent;
	return item;
}

BTreeItem* BTreeItem::prev()
{
	if (member.tree)
	{
		int index = this->index();
		if (member.parent)
		{
			return member.parent->child(index - 1);
		}
		return member.tree->topItem(index - 1);
	}
	return 0;
}
const BTreeItem* BTreeItem::prev() const
{
	if (member.tree)
	{
		int index = this->index();
		if (member.parent)
		{
			return member.parent->child(index - 1);
		}
		return member.tree->topItem(index - 1);
	}
	return 0;
}

BTreeItem* BTreeItem::next()
{
	if (member.tree)
	{
		int index = this->index();
		if (member.parent)
		{
			return member.parent->child(index + 1);
		}
		return member.tree->topItem(index + 1);
	}
	return 0;
}
const BTreeItem* BTreeItem::next() const
{
	if (member.tree)
	{
		int index = this->index();
		if (member.parent)
		{
			return member.parent->child(index + 1);
		}
		return member.tree->topItem(index + 1);
	}
	return 0;
}

int BTreeItem::index() const
{
	if (member.parent)
	{
		BArray<BTreeItemHolder>& children = item_member(member.parent)->children;
		for (int i = 0; i < children.size(); i++)
		{
			if (children[i] == this)
				return i;
		}
	}
	if (member.tree)
	{
		for (int i = 0; i < member.tree->topItemCount(); i++)
		{
			if (member.tree->topItem(i) == this)
				return i;
		}
	}
	return -1;
}
int BTreeItem::level() const
{
	int level = 0;
	const BTreeItem* item = this->parent();
	while (item)
	{
		level++;
		item = item_member(item)->parent;
	}
	return level;
}

bool BTreeItem::above(const BTreeItem* item) const
{
	if (!item)
		return false;
	BTreeItem* parent = item_member(item)->parent;
	while (parent)
	{
		if (parent == this)
			return true;
		parent = item_member(parent)->parent;
	}
	return false;
}
bool BTreeItem::under(const BTreeItem* item) const
{
	BTreeItem* parent = member.parent;
	while (parent)
	{
		if (parent == item)
			return true;
		parent = item_member(parent)->parent;
	}
	return false;
}
bool BTreeItem::contain(const BTreeItem* item) const
{
	if (!item)
		return false;
	for (int i = 0; i < member.children.size(); i++)
	{
		if (member.children[i] == item)
			return true;
	}
	return false;
}

BString BTreeItem::path(const char* split) const
{
	BString text = this->text();
	const BTreeItem* item = this->parent();
	while (item)
	{
		text.prepend(split);
		text.prepend(item->text());
		item = item->parent();
	}
	return text;
}
BString BTreeItem::path(const BString& split) const
{
	BString text = this->text();
	const BTreeItem* item = this->parent();
	while (item)
	{
		text.prepend(split);
		text.prepend(item->text());
		item = item->parent();
	}
	return text;
}

BString BTreeItem::pathTo(const BTreeItem* parent, const char* split) const
{
	if (this == parent)
		return BString();
	if (parent && !this->under(parent))
		return BString();
	BString text = this->text();
	const BTreeItem* item = this->parent();
	while (item && item != parent)
	{
		text.prepend(split);
		text.prepend(item->text());
		item = item->parent();
	}
	return text;
}
BString BTreeItem::pathTo(const BTreeItem* parent, const BString& split) const
{
	if (this == parent)
		return BString();
	if (parent && !this->under(parent))
		return BString();
	BString text = this->text();
	const BTreeItem* item = this->parent();
	while (item && item != parent)
	{
		text.prepend(split);
		text.prepend(item->text());
		item = item->parent();
	}
	return text;
}

BRect BTreeItem::rect() const
{
	if (member.tree)
	{
		const BRect& area = member.tree->area();
		BRect rect = member.rect + area.pos();
		rect.left() = area.left();
		rect.right() = area.right();
		return rect;
	}
	return member.rect;
}
BRect BTreeItem::iconRect() const
{
	return member.ia_imageRect;
}
BRect BTreeItem::textRect() const
{
	return member.ia_textRect;
}
BRect BTreeItem::textArea() const
{
	return member.ia_textArea;
}


